home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / aspisrc.zip / CREATE.C < prev    next >
C/C++ Source or Header  |  1992-01-26  |  32KB  |  1,303 lines

  1. /* Create a tar archive.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * Create a tar archive.
  22.  *
  23.  * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  *
  25.  * @(#)create.c 1.36 11/6/87 - gnu
  26.  */
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <stdio.h>
  30.  
  31. #ifndef V7
  32. #include <fcntl.h>
  33. #endif
  34.  
  35. #ifndef    __MSDOS__
  36. #include <sys/file.h>
  37. #include <sys/param.h>        /* for MAXPATHLEN */
  38. #include <pwd.h>
  39. #include <grp.h>
  40. #endif
  41.  
  42. #ifdef BSD42
  43. #include <sys/dir.h>
  44. #else
  45. #ifdef __MSDOS__
  46. #include "msd_dir.h"
  47. #else
  48. #ifdef USG
  49. #ifdef NDIR
  50. #include <ndir.h>
  51. #else
  52. #include <dirent.h>
  53. #endif
  54. #ifndef DIRECT
  55. #define direct dirent
  56. #endif
  57. #define DP_NAMELEN(x) strlen((x)->d_name)
  58. #else
  59. /*
  60.  * FIXME: On other systems there is no standard place for the header file
  61.  * for the portable directory access routines.  Change the #include line
  62.  * below to bring it in from wherever it is.
  63.  */
  64. #include "ndir.h"
  65. #endif
  66. #endif
  67. #endif
  68.  
  69. #ifndef DP_NAMELEN
  70. #define DP_NAMELEN(x)    (x)->d_namlen
  71. #endif
  72.  
  73. #ifdef USG
  74. #include <sys/sysmacros.h>    /* major() and minor() defined here */
  75. #endif
  76.  
  77. /*
  78.  * V7 doesn't have a #define for this.
  79.  */
  80. #ifndef O_RDONLY
  81. #define    O_RDONLY    0
  82. #endif
  83.  
  84. /*
  85.  * Most people don't have a #define for this.
  86.  */
  87. #ifndef    O_BINARY
  88. #define    O_BINARY    0
  89. #endif
  90.  
  91. #ifndef MAXPATHLEN
  92. #define MAXPATHLEN 1024
  93. #endif
  94.  
  95. #include "tar.h"
  96. #include "port.h"
  97.  
  98. extern struct stat hstat;        /* Stat struct corresponding */
  99.  
  100. #ifndef __MSDOS__
  101. extern dev_t ar_dev;
  102. extern ino_t ar_ino;
  103. #endif
  104.  
  105. /* JF */
  106. extern struct name *gnu_list_name;
  107.  
  108. /*
  109.  * If there are no symbolic links, there is no lstat().  Use stat().
  110.  */
  111. #ifndef S_IFLNK
  112. #define lstat stat
  113. #endif
  114.  
  115. extern char    *malloc();
  116. extern char    *strcpy();
  117. extern char    *strncpy();
  118. extern void    bzero();
  119. extern void    bcopy();
  120. extern int    errno;
  121.  
  122. extern void print_header();
  123.  
  124. union record *start_header();
  125. void finish_header();
  126. void finduname();
  127. void findgname();
  128. char *name_next();
  129. void to_oct();
  130. void dump_file();
  131.  
  132.  
  133. /* This code moved from tar.h since create.c is the only file that cares
  134.    about 'struct link's.  This means that other files might not have to
  135.    include sys/types.h any more.
  136.  */
  137.  
  138. struct link {
  139.     struct link    *next;
  140.     dev_t        dev;
  141.     ino_t        ino;
  142.     short        linkcount;
  143.     char        name[1];
  144. };
  145.  
  146. struct link    *linklist;    /* Points to first link in list */
  147.  
  148. static nolinks;            /* Gets set if we run out of RAM */
  149.  
  150. /*
  151.  * "Scratch" space to store the information about a sparse file before
  152.  * writing the info into the header or extended header
  153.  */
  154. /* struct sp_array     *sparsearray;*/
  155.  
  156. /* number of elts storable in the sparsearray */
  157. /*int     sparse_array_size = 10;*/
  158.  
  159. void
  160. create_archive()
  161. {
  162.     register char    *p;
  163.     char *name_from_list();
  164.  
  165.     open_archive(0);        /* Open for writing */
  166.  
  167.     if(f_gnudump) {
  168.         char buf[MAXNAMLEN],*q,*bufp;
  169.  
  170.         collect_and_sort_names();
  171.  
  172.         while(p=name_from_list())
  173.             dump_file(p,-1);
  174.         /* if(!f_dironly) { */
  175.             blank_name_list();
  176.             while(p=name_from_list()) {
  177.                 strcpy(buf,p);
  178.                 if(p[strlen(p)-1]!='/')
  179.                     strcat(buf,"/");
  180.                 bufp=buf+strlen(buf);
  181.                 for(q=gnu_list_name->dir_contents;q && *q;q+=strlen(q)+1) {
  182.                     if(*q=='Y') {
  183.                         strcpy(bufp,q+1);
  184.                         dump_file(buf,-1);
  185.                     }
  186.                 }
  187.             }
  188.         /* } */
  189.     
  190.     } else {
  191.         p = name_next(1);
  192.         if(!p)
  193.             dump_file(".", -1);
  194.         else {
  195.             do dump_file(p, -1);
  196.             while (p = name_next(1));
  197.         }
  198.     }
  199.  
  200.     write_mangled();
  201.     write_eot();
  202.     close_archive();
  203.     if(f_gnudump)
  204.         write_dir_file();
  205.     name_close();
  206. }
  207.  
  208. /*
  209.  * Dump a single file.  If it's a directory, recurse.
  210.  * Result is 1 for success, 0 for failure.
  211.  * Sets global "hstat" to stat() output for this file.
  212.  */
  213. void
  214. dump_file (p, curdev)
  215.     char    *p;            /* File name to dump */
  216.     int    curdev;            /* Device our parent dir was on */
  217. {
  218.     union record    *header;
  219.     char type;
  220.     extern char *save_name;        /* JF for multi-volume support */
  221.     extern long save_totsize;
  222.     extern long save_sizeleft;
  223.     union record    *exhdr;
  224.     char save_linkflag;
  225.     extern time_t new_time;
  226.     int sparse_ind = 0;
  227.  
  228.  
  229.     if(f_confirm && !confirm("add",p))
  230.         return;
  231.  
  232.     /*
  233.      * Use stat if following (rather than dumping) 4.2BSD's
  234.      * symbolic links.  Otherwise, use lstat (which, on non-4.2
  235.      * systems, is #define'd to stat anyway.
  236.      */
  237. #ifdef AIX
  238.     if (0 != f_follow_links ?
  239.         statx (p, &hstat, STATSIZE, STX_HIDDEN):
  240.         statx (p, &hstat, STATSIZE, STX_HIDDEN|STX_LINK))
  241. #else
  242.     if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat))
  243. #endif /* AIX */
  244.     {
  245. badperror:
  246.         msg_perror("can't add file %s",p);
  247. badfile:
  248.         errors++;
  249.         return;
  250.     }
  251.  
  252. #ifdef AIX
  253.     if (S_ISHIDDEN (hstat.st_mode)) {
  254.         char *new = (char *)allocate (strlen (p) + 2);
  255.         if (new) {
  256.             strcpy (new, p);
  257.             strcat (new, "@");
  258.             p = new;
  259.         }
  260.     }
  261. #endif /* AIX */
  262.  
  263.     /* See if we only want new files, and check if this one is too old to
  264.        put in the archive. */
  265.     if(   f_new_files
  266.        && !f_gnudump
  267.         && new_time>hstat.st_mtime
  268.         && (hstat.st_mode&S_IFMT)!=S_IFDIR
  269.         && (f_new_files>1 || new_time>hstat.st_ctime)) {
  270.         if(curdev<0) {
  271.             msg("%s: is unchanged; not dumped",p);
  272.         }
  273.         return;
  274.     }
  275.  
  276. #ifndef __MSDOS__
  277.     /* See if we are trying to dump the archive */
  278.     if(ar_dev && hstat.st_dev==ar_dev && hstat.st_ino==ar_ino) {
  279.         msg("%s is the archive; not dumped",p);
  280.         return;
  281.     }
  282. #endif
  283.     /*
  284.      * Check for multiple links.
  285.      *
  286.      * We maintain a list of all such files that we've written so
  287.      * far.  Any time we see another, we check the list and
  288.      * avoid dumping the data again if we've done it once already.
  289.      */
  290.     if (hstat.st_nlink > 1) switch (hstat.st_mode & S_IFMT) {
  291.         register struct link    *lp;
  292.  
  293.     case S_IFREG:            /* Regular file */
  294. #ifdef S_IFCTG
  295.     case S_IFCTG:            /* Contigous file */
  296. #endif
  297. #ifdef S_IFCHR
  298.     case S_IFCHR:            /* Character special file */
  299. #endif
  300.  
  301. #ifdef S_IFBLK
  302.     case S_IFBLK:            /* Block     special file */
  303. #endif
  304.  
  305. #ifdef S_IFIFO
  306.     case S_IFIFO:            /* Fifo      special file */
  307. #endif
  308.  
  309.         /* First quick and dirty.  Hashing, etc later FIXME */
  310.         for (lp = linklist; lp; lp = lp->next) {
  311.             if (lp->ino == hstat.st_ino &&
  312.                 lp->dev == hstat.st_dev) {
  313.                 char *link_name = lp->name;
  314.  
  315.                 /* We found a link. */
  316.                 hstat.st_size = 0;
  317.                 header = start_header(p, &hstat);
  318.                 if (header == NULL) goto badfile;
  319.                 while(!f_absolute_paths && *link_name == '/') {
  320.                     static int link_warn = 0;
  321.  
  322.                     if (!link_warn) {
  323.                         msg("Removing leading / from absolute links");
  324.                         link_warn++;
  325.                     }
  326.                     link_name++;
  327.                 }
  328.                   strncpy(header->header.linkname,
  329.                     link_name,NAMSIZ);
  330.                 if(header->header.linkname[NAMSIZ-1]) {
  331.                     char *mangled;
  332.                     extern char *find_mangled();
  333.  
  334.                     mangled=find_mangled(link_name);
  335.                     msg("%s: link name too long: mangled to %s",link_name,mangled);
  336.                     strncpy(header->header.linkname,mangled,NAMSIZ);
  337.                 }
  338.                 header->header.linkflag = LF_LINK;
  339.                 finish_header(header);
  340.         /* FIXME: Maybe remove from list after all links found? */
  341.                 return;        /* We dumped it */
  342.             }
  343.         }
  344.  
  345.         /* Not found.  Add it to the list of possible links. */
  346.         lp = (struct link *)malloc((unsigned)(sizeof(struct link)+strlen(p)));
  347.         if (!lp) {
  348.             if (!nolinks) {
  349.                 msg(
  350.     "no memory for links, they will be dumped as separate files");
  351.                 nolinks++;
  352.             }
  353.         }
  354.         lp->ino = hstat.st_ino;
  355.         lp->dev = hstat.st_dev;
  356.         strcpy(lp->name, p);
  357.         lp->next =